.text
.code64
.globl timer_handler
.globl pf_handler
.globl kb_handler
.globl system_call

// RAX is used to pass the system call number and return value during system calls, and cannot be corrupted
// `SAVE_CONTENT 0` and `RESTORE_CONTENT 0` are ignoring rax
// `SAVE_CONTENT 1` and `RESTORE_CONTENT 1` are destroying rax
.macro SAVE_CONTENT save_rax = 1
  pushq %rdi
  pushq %rsi
  pushq %rdx
  pushq %rcx
  .if \save_rax
  pushq %rax
  .endif
  pushq %r8
  pushq %r9
  pushq %r10
  pushq %r11
.endm

.macro RESTORE_CONTENT restore_rax = 1
  popq %r11
  popq %r10
  popq %r9
  popq %r8
  .if \restore_rax
  popq %rax
  .endif
  popq %rcx
  popq %rdx
  popq %rsi
  popq %rdi
.endm

timer_handler: // Clock interrupt handling function
  SAVE_CONTENT

  // Send the operation command word OCW2(EOI) to port 0x20 of 8259A
  mov $0x20, %al
  outb %al, $0x20

  call do_timer // c implementation, defined in kernel/sched.c

  RESTORE_CONTENT
  iretq

pf_handler: // Page Fault interrupt handling function
  SAVE_CONTENT

  mov %cr2, %rdi // Pass in a parameter: missing page address stored in register cr2 by the processor
  call do_page_fault // c implementation, defined in mm/memory.c
  add $8, %rsp // Stack pointer rsp moves 1B towards the kernel stack bottom, skipping error code

  RESTORE_CONTENT
  iretq

kb_handler: // Keyboard interrupt handling function
  SAVE_CONTENT

  call process_kb // c implementation, defined in drivers/atkdb.c

  // Send the operation command word OCW2(EOI) to port 0x20 of 8259A
  movb $0x20, %al
  outb %al, $0x20

  RESTORE_CONTENT
  iretq

// Bind to MSR, where the processor retrieves information when the user invokes a system call
system_call:
  mov %rsp, tss + 20 // %rsp -> tss.RSP2(tss+20B), Temporary storage of user stack top
  mov tss + 4, %rsp // tss.RSP0(tss+4B) -> %rsp, %rsp switch to the top of the process kernel stack

  pushq tss + 20 // User stack top push to kernel stack
  SAVE_CONTENT 0 // Do not save rax, CPU is used to pass system call number and return value

   // Invoke syscall by system call number
   // - %rax : system call number
   // - 8 : The width of each system call function pointer
  call *syscall_table(, %rax, 8) // defined in kernel/syscall.c

  RESTORE_CONTENT 0 // Still do not restore rax
  pop %rsp // Pop the user stack top from the top of the process kernel stack

  sysretq // Return to User State